package com.threadpool.juc;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**
 * https://www.cnblogs.com/java-chen-hao/p/10265938.html
 *
 * 1) newFixedThreadPool和newSingleThreadExecutor；
 * 主要问题是堆积的请求处理队列可能会耗费非常大的内存，甚至OOM
 * 2) newCachedThreadPool和newScheduledThreadPool；
 * 主要问题是线程数最大数是Integer.MAX_VALUE，可能创建数量非常多的线程，甚至OOM
 *
 * @author: chenhs
 * @date: Created in 10:32 2019/9/4
 **/
public class TestThreadPool3 {

    public static void main(String[] args) {
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("message-pool-%d").build();

        //Common Thread Pool
        /**
         * ArrayBlockingQueue基于数组结构的有界阻塞队列FIFO，其它都是无界。
         *
         * ArrayBlockingQueue是采用数组实现的有界阻塞线程安全队列。如果向已满的队列继续塞入元素，
         * 将导致当前的线程阻塞。如果向空队列获取元素，那么将导致当前线程阻塞。
         * https://www.jianshu.com/p/2c9e4abffb04
         *
         * 最大线程数 = maximumPoolSize
         * 待执行任务数【阻塞线程数，即进入等待队列线程数】= queue.length()
         * 最大任务数【总的线程数量】 = maximumPoolSize + queue.length()
         *
         *
         * 无法创建第11个线程，程序一直阻塞在那里。
         * 【又参见例子com.journaldev.threadpool.poolexecutor.WorkerPool】
         */
        ExecutorService pool = new ThreadPoolExecutor(2, 5, 0L, TimeUnit.MILLISECONDS
                , new ArrayBlockingQueue<>(5), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

        /**
         * newFixedThreadPool
         * 最大线程数设置为与核心线程数相等，则不会创建临时线程，创建的线程都是核心线程，线程也不会被回收。此时 keepAliveTime 设置为 0
         * （因为这里它是没用的，即使不为 0，线程池默认也不会回收 corePoolSize 内的线程），任务队列采用 LinkedBlockingQueue (FIFO)，无界队列，
         * 所以FixedThreadPool永远不会拒绝, 即饱和策略失效。
         *
         * 过程分析：刚开始，每提交一个任务都创建一个 worker，当 worker 的数量达到 nThreads 后，不再创建新的线程，而是把任务提交到
         * LinkedBlockingQueue 中，而且之后线程数始终为 nThreads。
         */
        ExecutorService fixedPool = new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

        /**
         * newSingleThreadExecutor
         * 初始化的线程池中只有一个线程，如果该线程异常结束，会重新创建一个新的线程继续执行任务，唯一的线程可以保证所提交任务的顺序执行。
         *
         * 由于使用了无界队列, 所以SingleThreadPool永远不会拒绝, 即饱和策略失效。
         */
        ExecutorService singlePool = new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        /**
         * newCachedThreadPool
         * 核心线程数为 0，最大线程数为 Integer.MAX_VALUE，keepAliveTime 为 60 秒，任务队列采用 SynchronousQueue，所以创建的线程都是临时线程，
         * 都可以被回收。
         *
         * 这种线程池对于任务可以比较快速地完成的情况有比较好的性能。如果线程空闲了 60 秒都没有任务，那么将关闭此线程并从线程池中移除。所以如果
         * 线程池空闲了很长时间也不会有问题，因为随着所有的线程都会被关闭，整个线程池不会占用任何的系统资源。
         */
        ExecutorService cachedPool = new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,
                new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());


        for (int i = 0; i < 20; i++) {
            cachedPool.execute(newTask());
        }

        //gracefully shutdown
        cachedPool.shutdown();
    }


    public static Runnable newTask() {
        return () -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " run!");
        };
    }


}
